﻿#region 참조 네임스페이스

using Skying.Runtime.InteropServices;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;

#endregion

namespace Skying.Resources
{
	/// <summary>
	/// 커서 그룹 리소스를 구성하는 클래스로 <see cref="Skying.Resources.Resource"/>로부터 파생된다.
	/// </summary>
	public class CursorGroupResource : Resource
	{
		#region 프로퍼티

		/// <summary>
		/// 커서 그룹 리소스 내의 커서의 목록을 가져온다.
		/// </summary>
		/// <remarks>
		/// <para>실제로는 편의를 위해 <see cref="System.Windows.Forms.Cursor"/>가 아닌 <see cref="System.Drawing.Icon"/>을 사용한다.</para>
		/// </remarks>
		public List<Icon> Values
		{
			get;
			private set;
		}

		#endregion

		#region 생성자/소멸자

		public CursorGroupResource(IntPtr moduleHandle, IntPtr type, IntPtr name)
			: base(moduleHandle, type, name)
		{
			
		}

		#endregion

		#region 리소스

		/// <summary>
		/// 커서 리소스를 구성한다.
		/// </summary>
		public override void CombineResource()
		{
			int newHeaderSize = Marshal.SizeOf(typeof(NewHeader));
			int cursorDirSize = Marshal.SizeOf(typeof(CursorDir));
			int localHeaderSize = Marshal.SizeOf(typeof(LocalHeader));
			int iconResDirSize = Marshal.SizeOf(typeof(IconResDir));

			byte[] groupBuffer = this.LoadResourceBinary(new IntPtr((int)ResourceTypes.RT_GROUP_CURSOR), this._nameHandle);

			if (groupBuffer.Length > 0)
			{
				byte[] newHeaderBinary = groupBuffer.Subset(newHeaderSize);

				NewHeader newHeader = MarshalExtensions.ConvertBinaryToStructure<NewHeader>(newHeaderBinary);

				// NewHeader에 정의된 리소스 개수만큼 목록을 생성한다.
				this.Values = new List<Icon>(newHeader.ResCount);

				// 초기 오프셋은 NewHeader 정보를 로드한 만큼부터 시작된다.
				int offset = newHeaderSize;

				for (int index = 0; index < newHeader.ResCount; index++)
				{
					byte[] cursorDirBinary = groupBuffer.Subset(offset, cursorDirSize);

					CursorDir cursorDir = MarshalExtensions.ConvertBinaryToStructure<CursorDir>(cursorDirBinary);

					// 오프셋은 CursorDir 정보를 로드한 만큼 증가한다.
					offset += cursorDirSize;

					// 실제 커서 이미지의 바이너리를 가져온다.
					byte[] cursorBinary = this.LoadResourceBinary(new IntPtr((int)ResourceTypes.RT_CURSOR), new IntPtr(cursorDir.ImageOffset));

					if (cursorBinary != null && cursorBinary.Length > 0)
					{
						byte[] localHeaderBinary = cursorBinary.Subset(localHeaderSize);

						LocalHeader localHeader = MarshalExtensions.ConvertBinaryToStructure<LocalHeader>(localHeaderBinary);

						using (MemoryStream stream = new MemoryStream())
						{
							using (BinaryWriter writer = new BinaryWriter(stream))
							{
								writer.Write(newHeader.Reserved);
								// Cursor 리소스에 대한 출력 형식을 Icon 형식으로 설정한다.
								writer.Write((ushort)1);
								// Cursor 리소스에 대한 이미지 개수를 1개로 정의한다.
								writer.Write((ushort)1);

								// IconResDir 정보를 설정한다.
								writer.Write((byte)cursorDir.Width);
								writer.Write((byte)cursorDir.Height);
								writer.Write((byte)0);
								writer.Write((byte)0);
								writer.Write(localHeader.XHotSpot);
								writer.Write(localHeader.YHotSpot);
								writer.Write(cursorDir.BytesInRes - (uint)localHeaderSize);
								writer.Write((ushort)(newHeaderSize + iconResDirSize));

								writer.Write((ushort)0);

								// 커서 이미지 바이너리를 복사한다.
								writer.Write(cursorBinary, localHeaderSize, (int)cursorDir.BytesInRes - localHeaderSize);

								stream.Seek(0, SeekOrigin.Begin);

								this.Values.Add(new Icon(stream));
							}
						}
					}
				}
			}
		}

		#endregion
	}
}